package work.zhengyun.demo.nio.groupchat;

import java.io.IOException;
import java.net.InetSocketAddress;
import java.nio.ByteBuffer;
import java.nio.channels.*;
import java.nio.charset.StandardCharsets;
import java.util.Iterator;

/**
 * @Author: zhengyun
 * @Email: 574860631@qq.com
 * @Date: 2021/3/24 10:43
 */
public class GroupChatServer {
    //
    private Selector selector;
    private ServerSocketChannel listenChannel;
    private static final int PROT = 6667;

    public GroupChatServer(){
        try {
            //得到选择器
            selector = Selector.open();
            //ServerSocketChannel
            listenChannel = ServerSocketChannel.open();
            //绑定端口
            listenChannel.socket().bind(new InetSocketAddress(PROT));
            //设置非阻塞模式
            listenChannel.configureBlocking(false);
            //将该listenChannel 注册到seletor
            listenChannel.register(selector, SelectionKey.OP_ACCEPT);

        }catch (Exception e){
            e.printStackTrace();
        }
    }
    private void listen(){
        try{
            while (true){
                int count = selector.select(2000);
                if(count>0){
                    Iterator<SelectionKey> iterator = selector.selectedKeys().iterator();
                    while(iterator.hasNext()){
                        //取出selectionKey
                        SelectionKey key = iterator.next();
                        //监听到accept
                        if(key.isAcceptable()){
                            SocketChannel sc = listenChannel.accept();
                            sc.configureBlocking(false);
                            sc.register(selector,SelectionKey.OP_READ);
                            //提示
                            System.out.println(sc.getRemoteAddress()+" 上线 ");

                        }
                        if(key.isReadable()){//通道发送read事件，即通道可读状态
                            //处理读
                            readDate(key);
                        }
                        //手动从集合中移动当前的selectionKey,防止重复操作
                        iterator.remove();
                    }

                }else {
                    System.out.println("等待。。。。");
                }
            }
        }catch (Exception e){
            e.printStackTrace();
        }finally {

        }
    }
    //读取客户端消息
    private void readDate(SelectionKey key){
        SocketChannel channel = null;
        try {
            //得到channel
            channel = (SocketChannel) key.channel();
            //创建buffer
            ByteBuffer buffer = ByteBuffer.allocate(1024);
            int count = channel.read(buffer);
            //根据count的值做处理
            if(count>0){
                String msg = new String(buffer.array());
                System.out.println("form 客户端："+msg);
                //向其他的客户端转发消息（去掉自己），专门写一个方法处理
                sendInfoToOtherClients(msg, channel);
            }
        }catch (IOException e){
            try{
                System.out.println(channel.getRemoteAddress()+"离线了...");
                //取消注册
                key.cancel();
                //关闭通道
                channel.close();
            }catch (IOException e2){
                e.printStackTrace();
            }
        }
    }
    //转发消息给其他客户端（通道）
    private void sendInfoToOtherClients(String msg,SocketChannel self) throws IOException{
        System.out.println("服务器转发消息中。。。");
        //遍历所有注册到selector上的SocketChannel，并排除self
        for(SelectionKey key : selector.keys()){
            //通过key 取出对应的SocketChannel
            Channel targetChannel = key.channel();
            if(targetChannel instanceof  SocketChannel && targetChannel !=self){
                //转型
                SocketChannel dest = (SocketChannel) targetChannel;
                //将msg 存储到buffer
                ByteBuffer buffer = ByteBuffer.wrap(msg.getBytes());
                //将buff 的数据写入通道
                dest.write(buffer);
            }
        }
    }
    public static void main(String[] args) {
        GroupChatServer groupChatServer = new GroupChatServer();
        groupChatServer.listen();
    }
}
